home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / Mail / RCS / collect.c,v < prev    next >
Encoding:
Text File  |  1990-02-14  |  13.0 KB  |  662 lines

  1. head     1.3;
  2. branch   ;
  3. access   ;
  4. symbols  ;
  5. locks    ; strict;
  6. comment  @ * @;
  7.  
  8.  
  9. 1.3
  10. date     90.02.14.15.01.01;  author jhh;  state Exp;
  11. branches ;
  12. next     1.2;
  13.  
  14. 1.2
  15. date     90.02.12.17.44.14;  author douglis;  state Exp;
  16. branches ;
  17. next     1.1;
  18.  
  19. 1.1
  20. date     90.02.12.17.43.41;  author douglis;  state Exp;
  21. branches ;
  22. next     ;
  23.  
  24.  
  25. desc
  26. @original from monet
  27. @
  28.  
  29.  
  30. 1.3
  31. log
  32. @removed longjmp patch
  33. @
  34. text
  35. @/*
  36.  * Copyright (c) 1980 Regents of the University of California.
  37.  * All rights reserved.
  38.  *
  39.  * Redistribution and use in source and binary forms are permitted
  40.  * provided that the above copyright notice and this paragraph are
  41.  * duplicated in all such forms and that any documentation,
  42.  * advertising materials, and other materials related to such
  43.  * distribution and use acknowledge that the software was developed
  44.  * by the University of California, Berkeley.  The name of the
  45.  * University may not be used to endorse or promote products derived
  46.  * from this software without specific prior written permission.
  47.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  48.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  49.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  50.  */
  51.  
  52. #ifndef lint
  53. static char sccsid[] = "@@(#)collect.c    5.17 (Berkeley) 1/16/89";
  54. #endif /* not lint */
  55.  
  56. /*
  57.  * Mail -- a mail program
  58.  *
  59.  * Collect input from standard input, handling
  60.  * ~ escapes.
  61.  */
  62.  
  63. #include "rcv.h"
  64. #include <sys/stat.h>
  65.  
  66. /*
  67.  * Read a message from standard output and return a read file to it
  68.  * or NULL on error.
  69.  */
  70.  
  71. /*
  72.  * The following hokiness with global variables is so that on
  73.  * receipt of an interrupt signal, the partial message can be salted
  74.  * away on dead.letter.
  75.  */
  76.  
  77. static    int    (*saveint)();        /* Previous SIGINT value */
  78. static    int    (*savehup)();        /* Previous SIGHUP value */
  79. static    int    (*savetstp)();        /* Previous SIGTSTP value */
  80. static    int    (*savettou)();        /* Previous SIGTTOU value */
  81. static    int    (*savettin)();        /* Previous SIGTTIN value */
  82. static    FILE    *collf;            /* File for saving away */
  83. static    int    hadintr;        /* Have seen one SIGINT so far */
  84.  
  85. static    jmp_buf    colljmp;        /* To get back to work */
  86. static    int    colljmp_p;        /* whether to long jump */
  87. static    jmp_buf    collabort;        /* To end collection with error */
  88.  
  89. FILE *
  90. collect(hp, printheaders)
  91.     struct header *hp;
  92. {
  93.     FILE *fbuf;
  94.     int lc, cc, escape, eofcount;
  95.     int collint(), collhup(), collstop();
  96.     register int c, t;
  97.     char linebuf[LINESIZE], *cp;
  98.     extern char tempMail[];
  99.     char getsub;
  100.     int omask;
  101.  
  102.     collf = NULL;
  103.     /*
  104.      * Start catching signals from here, but we're still die on interrupts
  105.      * until we're in the main loop.
  106.      */
  107.     omask = sigblock(sigmask(SIGINT) | sigmask(SIGHUP));
  108.     if ((saveint = signal(SIGINT, SIG_IGN)) != SIG_IGN)
  109.         signal(SIGINT, collint);
  110.     if ((savehup = signal(SIGHUP, SIG_IGN)) != SIG_IGN)
  111.         signal(SIGHUP, collhup);
  112.     savetstp = signal(SIGTSTP, collstop);
  113.     savettou = signal(SIGTTOU, collstop);
  114.     savettin = signal(SIGTTIN, collstop);
  115.     if (setjmp(collabort) || setjmp(colljmp)) {
  116.         remove(tempMail);
  117.         goto err;
  118.     }
  119.     sigsetmask(omask & ~(sigmask(SIGINT) | sigmask(SIGHUP)));
  120.  
  121.     noreset++;
  122.     if ((collf = fopen(tempMail, "w+")) == NULL) {
  123.         perror(tempMail);
  124.         goto err;
  125.     }
  126.     unlink(tempMail);
  127.  
  128.     /*
  129.      * If we are going to prompt for a subject,
  130.      * refrain from printing a newline after
  131.      * the headers (since some people mind).
  132.      */
  133.     t = GTO|GSUBJECT|GCC|GNL;
  134.     getsub = 0;
  135.     if (hp->h_subject == NOSTR && value("interactive") != NOSTR &&
  136.         (value("ask") != NOSTR || value("asksub") != NOSTR))
  137.         t &= ~GNL, getsub++;
  138.     if (printheaders) {
  139.         puthead(hp, stdout, t);
  140.         fflush(stdout);
  141.     }
  142.     if ((cp = value("escape")) != NOSTR)
  143.         escape = *cp;
  144.     else
  145.         escape = ESCAPE;
  146.     eofcount = 0;
  147.     hadintr = 0;
  148.  
  149.     if (!setjmp(colljmp)) {
  150.         if (getsub)
  151.             grabh(hp, GSUBJECT);
  152.     } else {
  153.         /*
  154.          * Come here for printing the after-signal message.
  155.          * Duplicate messages won't be printed because
  156.          * the write is aborted if we get a SIGTTOU.
  157.          */
  158. cont:
  159.         if (hadintr) {
  160.             fflush(stdout);
  161.             fprintf(stderr,
  162.             "\n(Interrupt -- one more to kill letter)\n");
  163.         } else {
  164.             printf("(continue)\n");
  165.             fflush(stdout);
  166.         }
  167.     }
  168.     for (;;) {
  169.         colljmp_p = 1;
  170.         c = readline(stdin, linebuf, LINESIZE);
  171.         colljmp_p = 0;
  172.         if (c < 0) {
  173.             if (value("interactive") != NOSTR &&
  174.                 value("ignoreeof") != NOSTR && ++eofcount < 25) {
  175.                 printf("Use \".\" to terminate letter\n");
  176.                 continue;
  177.             }
  178.             break;
  179.         }
  180.         eofcount = 0;
  181.         hadintr = 0;
  182.         if (linebuf[0] == '.' && linebuf[1] == '\0' &&
  183.             value("interactive") != NOSTR &&
  184.             (value("dot") != NOSTR || value("ignoreeof") != NOSTR))
  185.             break;
  186.         if (linebuf[0] != escape || value("interactive") == NOSTR) {
  187.             if (putline(collf, linebuf) < 0)
  188.                 goto err;
  189.             continue;
  190.         }
  191.         c = linebuf[1];
  192.         switch (c) {
  193.         default:
  194.             /*
  195.              * On double escape, just send the single one.
  196.              * Otherwise, it's an error.
  197.              */
  198.             if (c == escape) {
  199.                 if (putline(collf, &linebuf[1]) < 0)
  200.                     goto err;
  201.                 else
  202.                     break;
  203.             }
  204.             printf("Unknown tilde escape.\n");
  205.             break;
  206.         case 'C':
  207.             /*
  208.              * Dump core.
  209.              */
  210.             core();
  211.             break;
  212.         case '!':
  213.             /*
  214.              * Shell escape, send the balance of the
  215.              * line to sh -c.
  216.              */
  217.             shell(&linebuf[2]);
  218.             break;
  219.         case ':':
  220.             /*
  221.              * Escape to command mode, but be nice!
  222.              */
  223.             execute(&linebuf[2], 1);
  224.             goto cont;
  225.         case '.':
  226.             /*
  227.              * Simulate end of file on input.
  228.              */
  229.             goto out;
  230.         case 'q':
  231.             /*
  232.              * Force a quit of sending mail.
  233.              * Act like an interrupt happened.
  234.              */
  235.             hadintr++;
  236.             collint(SIGINT);
  237.             exit(1);
  238.         case 'h':
  239.             /*
  240.              * Grab a bunch of headers.
  241.              */
  242.             grabh(hp, GTO|GSUBJECT|GCC|GBCC);
  243.             goto cont;
  244.         case 't':
  245.             /*
  246.              * Add to the To list.
  247.              */
  248.             hp->h_to = cat(hp->h_to, extract(&linebuf[2], GTO));
  249.             break;
  250.         case 's':
  251.             /*
  252.              * Set the Subject list.
  253.              */
  254.             cp = &linebuf[2];
  255.             while (isspace(*cp))
  256.                 cp++;
  257.             hp->h_subject = savestr(cp);
  258.             break;
  259.         case 'c':
  260.             /*
  261.              * Add to the CC list.
  262.              */
  263.             hp->h_cc = cat(hp->h_cc, extract(&linebuf[2], GCC));
  264.             break;
  265.         case 'b':
  266.             /*
  267.              * Add stuff to blind carbon copies list.
  268.              */
  269.             hp->h_bcc = cat(hp->h_bcc, extract(&linebuf[2], GBCC));
  270.             break;
  271.         case 'd':
  272.             strcpy(linebuf + 2, getdeadletter());
  273.             /* fall into . . . */
  274.         case 'r':
  275.             /*
  276.              * Invoke a file:
  277.              * Search for the file name,
  278.              * then open it and copy the contents to collf.
  279.              */
  280.             cp = &linebuf[2];
  281.             while (isspace(*cp))
  282.                 cp++;
  283.             if (*cp == '\0') {
  284.                 printf("Interpolate what file?\n");
  285.                 break;
  286.             }
  287.             cp = expand(cp);
  288.             if (cp == NOSTR)
  289.                 break;
  290.             if (isdir(cp)) {
  291.                 printf("%s: Directory\n", cp);
  292.                 break;
  293.             }
  294.             if ((fbuf = fopen(cp, "r")) == NULL) {
  295.                 perror(cp);
  296.                 break;
  297.             }
  298.             printf("\"%s\" ", cp);
  299.             fflush(stdout);
  300.             lc = 0;
  301.             cc = 0;
  302.             while (readline(fbuf, linebuf, LINESIZE) >= 0) {
  303.                 lc++;
  304.                 if ((t = putline(collf, linebuf)) < 0) {
  305.                     fclose(fbuf);
  306.                     goto err;
  307.                 }
  308.                 cc += t;
  309.             }
  310.             fclose(fbuf);
  311.             printf("%d/%d\n", lc, cc);
  312.             break;
  313.         case 'w':
  314.             /*
  315.              * Write the message on a file.
  316.              */
  317.             cp = &linebuf[2];
  318.             while (*cp == ' ' || *cp == '\t')
  319.                 cp++;
  320.             if (*cp == '\0') {
  321.                 fprintf(stderr, "Write what file!?\n");
  322.                 break;
  323.             }
  324.             if ((cp = expand(cp)) == NOSTR)
  325.                 break;
  326.             rewind(collf);
  327.             exwrite(cp, collf, 1);
  328.             break;
  329.         case 'm':
  330.         case 'M':
  331.         case 'f':
  332.         case 'F':
  333.             /*
  334.              * Interpolate the named messages, if we
  335.              * are in receiving mail mode.  Does the
  336.              * standard list processing garbage.
  337.              * If ~f is given, we don't shift over.
  338.              */
  339.             if (forward(linebuf + 2, collf, c) < 0)
  340.                 goto err;
  341.             goto cont;
  342.         case '?':
  343.             if ((fbuf = fopen(THELPFILE, "r")) == NULL) {
  344.                 perror(THELPFILE);
  345.                 break;
  346.             }
  347.             while ((t = getc(fbuf)) != EOF)
  348.                 (void) putchar(t);
  349.             fclose(fbuf);
  350.             break;
  351.         case 'p':
  352.             /*
  353.              * Print out the current state of the
  354.              * message without altering anything.
  355.              */
  356.             rewind(collf);
  357.             printf("-------\nMessage contains:\n");
  358.             puthead(hp, stdout, GTO|GSUBJECT|GCC|GBCC|GNL);
  359.             while ((t = getc(collf)) != EOF)
  360.                 (void) putchar(t);
  361.             goto cont;
  362.         case '|':
  363.             /*
  364.              * Pipe message through command.
  365.              * Collect output as new message.
  366.              */
  367.             rewind(collf);
  368.             mespipe(collf, &linebuf[2]);
  369.             goto cont;
  370.         case 'v':
  371.         case 'e':
  372.             /*
  373.              * Edit the current message.
  374.              * 'e' means to use EDITOR
  375.              * 'v' means to use VISUAL
  376.              */
  377.             rewind(collf);
  378.             mesedit(collf, c);
  379.             goto cont;
  380.         }
  381.     }
  382.     goto out;
  383. err:
  384.     if (collf != NULL) {
  385.         fclose(collf);
  386.         collf = NULL;
  387.     }
  388. out:
  389.     if (collf != NULL)
  390.         rewind(collf);
  391.     noreset--;
  392.     sigblock(sigmask(SIGINT) | sigmask(SIGHUP));
  393.     signal(SIGINT, saveint);
  394.     signal(SIGHUP, savehup);
  395.     signal(SIGTSTP, savetstp);
  396.     signal(SIGTTOU, savettou);
  397.     signal(SIGTTIN, savettin);
  398.     sigsetmask(omask);
  399.     return collf;
  400. }
  401.  
  402. /*
  403.  * Write a file, ex-like if f set.
  404.  */
  405.  
  406. exwrite(name, fp, f)
  407.     char name[];
  408.     FILE *fp;
  409. {
  410.     register FILE *of;
  411.     register int c;
  412.     long cc;
  413.     int lc;
  414.     struct stat junk;
  415.  
  416.     if (f) {
  417.         printf("\"%s\" ", name);
  418.         fflush(stdout);
  419.     }
  420.     if (stat(name, &junk) >= 0 && (junk.st_mode & S_IFMT) == S_IFREG) {
  421.         if (!f)
  422.             fprintf(stderr, "%s: ", name);
  423.         fprintf(stderr, "File exists\n");
  424.         return(-1);
  425.     }
  426.     if ((of = fopen(name, "w")) == NULL) {
  427.         perror(NOSTR);
  428.         return(-1);
  429.     }
  430.     lc = 0;
  431.     cc = 0;
  432.     while ((c = getc(fp)) != EOF) {
  433.         cc++;
  434.         if (c == '\n')
  435.             lc++;
  436.         (void) putc(c, of);
  437.         if (ferror(of)) {
  438.             perror(name);
  439.             fclose(of);
  440.             return(-1);
  441.         }
  442.     }
  443.     fclose(of);
  444.     printf("%d/%ld\n", lc, cc);
  445.     fflush(stdout);
  446.     return(0);
  447. }
  448.  
  449. /*
  450.  * Edit the message being collected on fp.
  451.  * On return, make the edit file the new temp file.
  452.  */
  453. mesedit(fp, c)
  454.     FILE *fp;
  455. {
  456.     int (*sigint)() = signal(SIGINT, SIG_IGN);
  457.     FILE *nf = run_editor(fp, (off_t)-1, c, 0);
  458.  
  459.     if (nf != NULL) {
  460.         fseek(nf, (off_t)0, 2);
  461.         collf = nf;
  462.         fclose(fp);
  463.     }
  464.     (void) signal(SIGINT, sigint);
  465. }
  466.  
  467. /*
  468.  * Pipe the message through the command.
  469.  * Old message is on stdin of command;
  470.  * New message collected from stdout.
  471.  * Sh -c must return 0 to accept the new message.
  472.  */
  473. mespipe(fp, cmd)
  474.     FILE *fp;
  475.     char cmd[];
  476. {
  477.     FILE *nf;
  478.     int (*sigint)() = signal(SIGINT, SIG_IGN);
  479.     extern char tempEdit[];
  480.  
  481.     if ((nf = fopen(tempEdit, "w+")) == NULL) {
  482.         perror(tempEdit);
  483.         goto out;
  484.     }
  485.     (void) unlink(tempEdit);
  486.     /*
  487.      * stdin = current message.
  488.      * stdout = new message.
  489.      */
  490.     if (run_command(cmd, 0, fileno(fp), fileno(nf), NOSTR) < 0) {
  491.         (void) fclose(nf);
  492.         goto out;
  493.     }
  494.     if (fsize(nf) == 0) {
  495.         fprintf(stderr, "No bytes from \"%s\" !?\n", cmd);
  496.         (void) fclose(nf);
  497.         goto out;
  498.     }
  499.     /*
  500.      * Take new files.
  501.      */
  502.     (void) fseek(nf, 0L, 2);
  503.     collf = nf;
  504.     (void) fclose(fp);
  505. out:
  506.     (void) signal(SIGINT, sigint);
  507. }
  508.  
  509. /*
  510.  * Interpolate the named messages into the current
  511.  * message, preceding each line with a tab.
  512.  * Return a count of the number of characters now in
  513.  * the message, or -1 if an error is encountered writing
  514.  * the message temporary.  The flag argument is 'm' if we
  515.  * should shift over and 'f' if not.
  516.  */
  517. forward(ms, fp, f)
  518.     char ms[];
  519.     FILE *fp;
  520. {
  521.     register int *msgvec;
  522.     extern char tempMail[];
  523.     struct ignoretab *ig;
  524.     char *tabst;
  525.  
  526.     msgvec = (int *) salloc((msgCount+1) * sizeof *msgvec);
  527.     if (msgvec == (int *) NOSTR)
  528.         return(0);
  529.     if (getmsglist(ms, msgvec, 0) < 0)
  530.         return(0);
  531.     if (*msgvec == 0) {
  532.         *msgvec = first(0, MMNORM);
  533.         if (*msgvec == NULL) {
  534.             printf("No appropriate messages\n");
  535.             return(0);
  536.         }
  537.         msgvec[1] = NULL;
  538.     }
  539.     if (f == 'f' || f == 'F')
  540.         tabst = NOSTR;
  541.     else if ((tabst = value("tabstr")) == NOSTR)
  542.         tabst = "\t";
  543.     ig = isupper(f) ? NULL : ignore;
  544.     printf("Interpolating:");
  545.     for (; *msgvec != 0; msgvec++) {
  546.         struct message *mp = message + *msgvec - 1;
  547.  
  548.         touch(mp);
  549.         printf(" %d", *msgvec);
  550.         if (send(mp, fp, ig, tabst) < 0) {
  551.             perror(tempMail);
  552.             return(-1);
  553.         }
  554.     }
  555.     printf("\n");
  556.     return(0);
  557. }
  558.  
  559. /*
  560.  * Print (continue) when continued after ^Z.
  561.  */
  562. /*ARGSUSED*/
  563. collstop(s)
  564. {
  565.     int (*old_action)() = signal(s, SIG_DFL);
  566.  
  567.     sigsetmask(sigblock(0) & ~sigmask(s));
  568.     kill(0, s);
  569.     sigblock(sigmask(s));
  570.     signal(s, old_action);
  571.     if (colljmp_p) {
  572.         colljmp_p = 0;
  573.         hadintr = 0;
  574.         longjmp(colljmp, 1);
  575.     }
  576. }
  577.  
  578. /*
  579.  * On interrupt, come here to save the partial message in ~/dead.letter.
  580.  * Then jump out of the collection loop.
  581.  */
  582. /*ARGSUSED*/
  583. collint(s)
  584. {
  585.     /*
  586.      * the control flow is subtle, because we can be called from ~q.
  587.      */
  588.     if (!hadintr) {
  589.         if (value("ignore") != NOSTR) {
  590.             puts("@@");
  591.             fflush(stdout);
  592.             clearerr(stdin);
  593.             return;
  594.         }
  595.         hadintr = 1;
  596.         longjmp(colljmp, 1);
  597.     }
  598.     rewind(collf);
  599.     if (value("nosave") == NOSTR)
  600.         savedeadletter(collf);
  601.     longjmp(collabort, 1);
  602. }
  603.  
  604. /*ARGSUSED*/
  605. collhup(s)
  606. {
  607.     rewind(collf);
  608.     savedeadletter(collf);
  609.     /*
  610.      * Let's pretend nobody else wants to clean up,
  611.      * a true statement at this time.
  612.      */
  613.     exit(1);
  614. }
  615.  
  616. savedeadletter(fp)
  617.     register FILE *fp;
  618. {
  619.     register FILE *dbuf;
  620.     register int c;
  621.     char *cp;
  622.  
  623.     if (fsize(fp) == 0)
  624.         return;
  625.     cp = getdeadletter();
  626.     c = umask(077);
  627.     dbuf = fopen(cp, "a");
  628.     (void) umask(c);
  629.     if (dbuf == NULL)
  630.         return;
  631.     while ((c = getc(fp)) != EOF)
  632.         (void) putc(c, dbuf);
  633.     fclose(dbuf);
  634.     rewind(fp);
  635. }
  636. @
  637.  
  638.  
  639. 1.2
  640. log
  641. @fix for ds3100 signal mask problem
  642. @
  643. text
  644. @a128 7
  645. #ifdef ds3100
  646.             /*
  647.              * The ds3100 longjmp doesn't restore signal masks.
  648.              */
  649.             sigsetmask(0);
  650.             
  651. #endif /* ds3100 */
  652. @
  653.  
  654.  
  655. 1.1
  656. log
  657. @Initial revision
  658. @
  659. text
  660. @d129 7
  661. @
  662.